home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d935.lha / AmiCDROM / device.c < prev    next >
C/C++ Source or Header  |  1993-12-20  |  34KB  |  1,229 lines

  1. /* device.c:
  2.  *
  3.  * Handler for ISO-9660 (+ Rock Ridge) + HFS CDROM filing system.
  4.  * Based on DOSDEV V1.10 (2 Nov 87) by Matthew Dillon.
  5.  *
  6.  * ----------------------------------------------------------------------
  7.  * This code is (C) Copyright 1993 by Frank Munkert.
  8.  * All rights reserved.
  9.  * This software may be freely distributed and redistributed for
  10.  * non-commercial purposes, provided this notice is included.
  11.  * ----------------------------------------------------------------------
  12.  * History:
  13.  * 
  14.  * 26-Nov-93   fmu   Some packets are now handled even if no disk
  15.  *                   is inserted.
  16.  * 21-Nov-93   fmu   - User programmable diskchange check interval.
  17.  *                   - Better support for ACTION_INHIBIT.
  18.  *                   - Handles filenames with ';'.
  19.  * 15-Nov-93   fmu   Missing return value for 'handler' inserted.
  20.  * 14-Nov-93   fmu   Added ACTION_USER packet for 'cdcontrol' program.
  21.  * 15-Oct-93   fmu   Adapted to new VOLUME structure.
  22.  * 10-Oct-93   fmu   - Creates volume node for 'no DOS' disks.
  23.  *             - Volume node now contains the correct volume
  24.  *               creation date.
  25.  * 09-Oct-93   fmu   - New format for mountlist startup field.
  26.  *             - SAS/C support.
  27.  *             - Debug process assembly tag adapted to small
  28.  *               memory model.
  29.  *             - Get_Startup moved to file devsupp.c.
  30.  * 03-Oct-93   fmu   - New buffering options 'S' and 'C'.
  31.  *                   - Fixed bug in cdlock.
  32.  *             - Fixed bug in ACTION_CURRENT_VOLUME.
  33.  * 27-Sep-93   fmu   Added ACTION_SAME_LOCK
  34.  * 25-Sep-93   fmu   - Send 'disk inserted' / 'disk removed' event via
  35.  *                     input.device if disk has been changed.
  36.  *                   - Corrected bug in ACTION_DISK_INFO.
  37.  * 24-Sep-93   fmu   - Added fast memory option 'F'.
  38.  *                   - Added ACTION_IS_FILESYSTEM.
  39.  *                   - Added 'write protected' error for write actions.
  40.  *                   - Added ACTION_CURRENT_VOLUME.
  41.  *                   - Unload handler code after ACTION_DIE.
  42.  *                   - Immediately terminate program if called from CLI.
  43.  *                   - Added library version number.
  44.  *                   - Set volume label to "Unnamed" for disks without name.
  45.  * 16-Sep-93   fmu   Added code to detect whether a lock stems from the
  46.  *                   current volume or from another volume which has
  47.  *                   been removed from the drive.
  48.  */
  49.  
  50. /*
  51.  *  Debugging routines are disabled by simply attempting to open the
  52.  *  file "debugoff", turned on again with "debugon".  No prefix may be
  53.  *  attached to these names (you must be CD'd to TEST:).
  54.  *
  55.  *  See Documentation for a detailed discussion.
  56.  */
  57.  
  58. #include <stdlib.h>
  59. #include <string.h>
  60.  
  61. #if defined(_DCC) && !defined(REGISTERED)
  62. #define abs
  63. #endif
  64.  
  65. #include "device.h"
  66. #include "cdrom.h"
  67. #include "generic.h"
  68. #include "intui.h"
  69. #include "devsupp.h"
  70. #include "cdcontrol.h"
  71. #include "params.h"
  72.  
  73. /*
  74.  *  Since this code might be called several times in a row without being
  75.  *  unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  76.  *  for any global/static assignments that might be changed by running the
  77.  *  code.
  78.  */
  79.  
  80. PROC    *DosProc;     /* Our Process                        */
  81. DEVNODE *DosNode;     /* Our DOS node.. created by DOS for us            */
  82. DEVLIST *DevList;     /* Device List structure for our volume node       */
  83.  
  84. #if !defined(_DCC) || defined(REGISTERED)
  85. EXECLIB *SysBase;     /* EXEC library base                */
  86. #endif
  87. DOSLIB    *DOSBase;     /* DOS library base for debug process        */
  88. LIB    *UtilityBase; /* Utility library for miscellaneous tasks     */
  89.  
  90. CDROM   *g_cd;
  91. VOLUME  *g_volume;
  92. CDROM_OBJ *g_top_level_obj;
  93. char    *g_vol_name;
  94.  
  95. PORT *g_timer_mp;           /*  timer message port        */
  96. struct timerequest *g_timer_io; /*  timer i/o request        */
  97. ULONG g_timer_sigbit;
  98. ULONG g_dos_sigbit;
  99.  
  100. char    g_device[80];        /* SCSI device name */
  101. short    g_unit;            /* SCSI unit */
  102. short    g_use_rock_ridge;    /* Use Rock Ridge flag 'R' */
  103. short    g_map_to_lowercase;    /* Map to lower case flag 'L' */
  104. int     g_trackdisk;        /* Use trackdisk calls instead of SCSI-direct */
  105. int    g_fastmem;        /* Use fast memory for SCSI buffers */
  106. int    g_files_pending;    /* Number of open file handles */
  107.  
  108. int    g_std_buffers;        /* Number of buffers for standard SCSI access */
  109. int    g_file_buffers;        /* Number of buffers for contiguous reads */
  110.  
  111. t_bool    g_show_version_numbers; /* Show version numbers */
  112.  
  113. int    g_scan_interval;    /* Time between successive diskchange checks */
  114.  
  115. t_bool    g_disk_inserted;    /* Is a disk inserted? */
  116.  
  117. char    g_play_cdda_command[80];/* Command invoked if appicon is activated */
  118.  
  119. struct MsgPort *DosTask;
  120.  
  121. #if !defined(NDEBUG) || defined(DEBUG_SECTORS)
  122.             /*    DEBUGGING            */
  123. PORT *Dbport;        /*    owned by the debug process    */
  124. PORT *Dback;        /*    owned by the DOS device driver    */
  125. short DBDisable;
  126. MSG DummyMsg;        /*    Dummy message that debug proc can use    */
  127. #endif
  128.  
  129. void *dosalloc(ulong);
  130. void dosfree (ulong *);
  131. void btos(LONG, char *);
  132. void *NextNode (NODE *);
  133. void *GetHead (LIST *);
  134. LOCK *cdlock(CDROM_OBJ *, int);
  135. void cdunlock (LOCK *);
  136. CDROM_OBJ *getlockfile (LONG);
  137. char *typetostr (int);
  138. void returnpacket(struct DosPacket *);
  139. int packetsqueued (void);
  140. int Check_For_Volume_Name_Prefix (char *);
  141. void Fill_FileInfoBlock (FIB *, CDROM_INFO *, VOLUME *);
  142. void Mount (void);
  143. void Unmount (int);
  144. int Mount_Check (void);
  145. void Check_Disk (void);
  146. void Send_Timer_Request (void);
  147. void Cleanup_Timer_Device (void);
  148. int Open_Timer_Device (void);
  149. void Send_Event (int);
  150.  
  151. /*
  152.  *  Don't call the entry point main().  This way, if you make a mistake
  153.  *  with the compile options you'll get a link error.
  154.  */
  155.  
  156. #if defined(LATTICE)
  157. int __saveds handler (void)
  158. #elif defined(_DCC) && !defined(REGISTERED)
  159. int _main (void)
  160. #elif defined(_DCC) && defined(REGISTERED)
  161. __geta4 int handler (void)
  162. #else
  163. int handler (void)
  164. #endif
  165. {
  166.     register PACKET *packet;
  167.     register short   error;
  168.     MSG     *msg;
  169.     ubyte   notdone = 1;
  170.     char    buf[256];
  171.     void    *tmp;
  172.     ULONG   signals;
  173.     ubyte   playing = FALSE;
  174.  
  175.     /*
  176.      *    Initialize all global variables. SysBase MUST be initialized before
  177.      *  we can make Exec calls. The DOS library is opened for the debug
  178.      *  process only.
  179.      */
  180.  
  181. #if !defined(_DCC) || defined(REGISTERED)
  182.     SysBase = *(EXECLIB **) 4L;
  183. #endif
  184.     DosProc = (PROC *) FindTask(NULL);
  185.     if (DosProc->pr_CLI)
  186.       return RETURN_FAIL;
  187.     DOSBase = (DOSLIB *) OpenLibrary ((UBYTE *) "dos.library",37);
  188.     UtilityBase = (LIB *) OpenLibrary ((UBYTE *) "utility.library",37);
  189.  
  190.     BUG2(DBDisable = 0;)                /*  Init. globals    */
  191.     BUG2(Dbport = Dback = NULL;)
  192.     DevList = NULL;
  193.     {
  194.     WaitPort(&DosProc->pr_MsgPort);     /*  Get Startup Packet    */
  195.     msg = GetMsg(&DosProc->pr_MsgPort);
  196.     packet = (PACKET *)msg->mn_Node.ln_Name;
  197.  
  198.     /*
  199.      *  Loading DosNode->dn_Task causes DOS *NOT* to startup a new
  200.      *  instance of the device driver for every reference.    E.G. if
  201.      *  you were writing a CON device you would want this field to
  202.      *  be NULL.
  203.      */
  204.  
  205.         DosNode = BTOC(packet->dp_Arg3);
  206.  
  207.     Init_Intui ();
  208.  
  209.     if (UtilityBase && DOSBase && Get_Startup (packet->dp_Arg2)) {
  210.         /*
  211.          *    Set dn_Task field which tells DOS not to startup a new
  212.          *    process on every reference.
  213.          */
  214.  
  215.           DosNode->dn_Task = &DosProc->pr_MsgPort;
  216.         packet->dp_Res1 = DOS_TRUE;
  217.          packet->dp_Res2 = 0;
  218.         
  219.         DosTask = DosNode->dn_Task;
  220.  
  221.     } else {                /*    couldn't open dos.library   */
  222.         packet->dp_Res1 = DOS_FALSE;
  223.         returnpacket(packet);
  224.         return 0;                /*    exit process            */
  225.     }
  226.     returnpacket(packet);
  227.     }
  228.  
  229.     g_disk_inserted = (Test_Unit_Ready (g_cd) ||
  230.                    Test_Unit_Ready (g_cd));
  231.  
  232.     /*
  233.      *    Initialize debugging code
  234.      */
  235.  
  236.     BUG2(dbinit();)
  237.  
  238.     BUG(dbprintf("%d std buffers, %d file buffers\n",
  239.              g_std_buffers, g_file_buffers);)
  240.  
  241.     g_timer_sigbit = 0;
  242.     if (g_scan_interval > 0) {
  243.       /* Initialize timer: */
  244.       if (Open_Timer_Device ())
  245.         Send_Timer_Request ();
  246.     }
  247.  
  248.     g_vol_name = dosalloc (128);
  249.  
  250.     /* Mount volume (if any disk is inserted): */
  251.     Mount ();
  252.  
  253.     g_dos_sigbit = 1L << DosProc->pr_MsgPort.mp_SigBit;
  254.  
  255.     g_files_pending = 0;
  256.  
  257.     /*
  258.      *    Here begins the endless loop, waiting for requests over our
  259.      *    message port and executing them.  Since requests are sent over
  260.      *    our message port, this precludes being able to call DOS functions
  261.      *    ourselves (that is why the debugging routines are a separate process)
  262.      */
  263.  
  264. top:
  265.     for (; notdone;) {
  266.     signals = Wait(g_dos_sigbit | g_timer_sigbit | g_app_sigbit);
  267.     if (signals & g_timer_sigbit) {
  268.       GetMsg (g_timer_mp);
  269.       Check_Disk ();
  270.       Send_Timer_Request ();
  271.     }
  272.     if (signals & g_app_sigbit) {
  273.       struct Message *msg;
  274.       while (msg = GetMsg (g_app_port)) {
  275.         ReplyMsg (msg);
  276.         if (g_play_cdda_command[0])
  277.           SystemTags ((UBYTE *) g_play_cdda_command,
  278.                   SYS_Input, Open ((UBYTE *) "NIL:", MODE_OLDFILE),
  279.                   SYS_Output, Open ((UBYTE *) "NIL:", MODE_NEWFILE),
  280.                   SYS_Asynch, TRUE,
  281.               TAG_END);
  282.         else {
  283.           if (playing)
  284.             Stop_Play_Audio (g_cd);
  285.           else
  286.             Start_Play_Audio (g_cd);
  287.           playing = !playing;
  288.         }
  289.       }
  290.     }
  291.     if (!(signals & g_dos_sigbit))
  292.       continue;
  293.     while (msg = GetMsg(&DosProc->pr_MsgPort)) {
  294.         packet = (PACKET *)msg->mn_Node.ln_Name;
  295.         packet->dp_Res1 = DOS_TRUE;
  296.         packet->dp_Res2 = 0;
  297.         error = 0;
  298. #ifndef NDEBUG
  299.         dbprintf("Packet: %3ld %08lx %08lx %08lx %10s ",
  300.         packet->dp_Type,
  301.         packet->dp_Arg1, packet->dp_Arg2,
  302.         packet->dp_Arg3,
  303.         typetostr(packet->dp_Type)
  304.         );
  305. #endif
  306.  
  307.         if (DevList == NULL) {
  308.           switch (packet->dp_Type) {
  309.           /* packets we will handle even if no disk is inserted: */
  310.           case ACTION_DIE:
  311.           case ACTION_USER:
  312.           case ACTION_IS_FILESYSTEM:
  313.           case ACTION_INHIBIT:
  314.           case ACTION_MORE_CACHE:
  315.           case ACTION_FLUSH:
  316.         break;
  317.           /* packets we cannot handle because no disk is inserted: */
  318.           default:
  319.             packet->dp_Res1 = DOS_FALSE;
  320.             packet->dp_Res2 = (g_disk_inserted ? ERROR_NOT_A_DOS_DISK :
  321.                    ERROR_NO_DISK);
  322.             BUG(dbprintf("ERR=%ld\n", (long) packet->dp_Res2);)
  323.             returnpacket(packet);
  324.                 continue;            
  325.           }
  326.         }
  327.  
  328.         switch(packet->dp_Type) {
  329.         case ACTION_DIE:        /*    attempt to die?             */
  330.         notdone = 0;        /*    try to die                */
  331.         break;
  332.         case ACTION_USER:        /*  Mode,Par1,Par2            Bool    */
  333.             error = Handle_Control_Packet (packet->dp_Arg1,
  334.                            packet->dp_Arg2,
  335.                            packet->dp_Arg3);
  336.             break;
  337.         case ACTION_FINDINPUT:  /*  FileHandle,Lock,Name        Bool    */
  338.         {
  339.             if (Mount_Check ()) {
  340.               CDROM_OBJ *obj;
  341.               CDROM_OBJ *parentdir = getlockfile(packet->dp_Arg2);
  342.               int       offs;
  343.  
  344.               if (parentdir->volume != g_volume) {
  345.                   /* old lock from another disk: */
  346.             error = ERROR_OBJECT_NOT_FOUND;
  347.             goto openbreak;
  348.               }
  349.               
  350.               btos(packet->dp_Arg3,buf);
  351.               BUG(dbprintf("'%s' ", buf);)
  352.               offs = Check_For_Volume_Name_Prefix (buf);
  353.               if (obj = Open_Object (parentdir, buf + offs)) {
  354.             if (obj->directory_f) {
  355.                 error = ERROR_OBJECT_WRONG_TYPE;
  356.                 goto openbreak;
  357.             }
  358.               } else {
  359.             if (iso_errno == ISOERR_ILLEGAL_NAME) {
  360.                 error = ERROR_INVALID_COMPONENT_NAME;
  361.                 goto openbreak;
  362.             } else if (iso_errno == ISOERR_NOT_FOUND)
  363.                   error = ERROR_OBJECT_NOT_FOUND;
  364.             else if (iso_errno == ISOERR_NO_MEMORY) {
  365.               error = ERROR_NO_FREE_STORE;
  366.               goto openbreak;
  367.             } else {
  368.               error = 333;
  369.               goto openbreak;
  370.             }
  371.               }
  372.               if (!error) {
  373.                 g_files_pending++;
  374.               ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long) obj;
  375.               }
  376.             } else
  377.               error = ERROR_NO_DISK;
  378.         }
  379.           openbreak:
  380.         break;
  381.         case ACTION_READ:        /*     FHArg1,CPTRBuffer,Length   ActLength  */
  382.         {
  383.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  384.             char      *ptr = (char *) packet->dp_Arg2;
  385.             long    length = packet->dp_Arg3;
  386.             int     actual;
  387.  
  388.             if (obj->volume != g_volume) {
  389.               /* old lock from another disk: */
  390.               error = ERROR_OBJECT_NOT_FOUND;
  391.               break;
  392.             }
  393.             actual = Read_From_File (obj, ptr, length);
  394.             packet->dp_Res1 = actual;
  395.         }
  396.         break;
  397.         case ACTION_END:        /*     FHArg1             Bool:TRUE  */
  398.         {
  399.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  400.  
  401.             Close_Object (obj);
  402.             g_files_pending--;
  403.         }
  404.         break;
  405.         case ACTION_SEEK:        /*     FHArg1,Position,Mode        OldPosition*/
  406.             {
  407.             CDROM_OBJ *obj = (CDROM_OBJ *) packet->dp_Arg1;
  408.             long offset = packet->dp_Arg2;
  409.             int mode = packet->dp_Arg3;
  410.             
  411.             if (obj->volume != g_volume) {
  412.               /* old lock from another disk: */
  413.               error = ERROR_OBJECT_NOT_FOUND;
  414.               break;
  415.             }
  416.             packet->dp_Res1 = obj->pos;
  417.             if (!Seek_Position (obj, offset, mode)) {
  418.               error = ERROR_SEEK_ERROR;
  419.               packet->dp_Res1 = -1;
  420.             }
  421.         }
  422.         break;
  423.         case ACTION_EXAMINE_NEXT: /*   Lock,Fib              Bool     */
  424.         {
  425.             FIB       *fib = BTOC (packet->dp_Arg2);
  426.             CDROM_OBJ *dir = getlockfile (packet->dp_Arg1);
  427.             CDROM_INFO info;
  428.  
  429.             if (dir->volume != g_volume) {
  430.               /* old lock from another disk: */
  431.               error = ERROR_OBJECT_NOT_FOUND;
  432.               break;
  433.             }
  434.             if (!dir->directory_f) {
  435.             error = ERROR_OBJECT_WRONG_TYPE;
  436.             break;
  437.             }
  438.             if (Examine_Next (dir, &info,
  439.                           (unsigned long *) &fib->fib_DiskKey)) {
  440.               error = 0;
  441.               Fill_FileInfoBlock (fib, &info, dir->volume);
  442.             } else {
  443.               error = ERROR_NO_MORE_ENTRIES;
  444.             }
  445.             break;
  446.         }
  447.         case ACTION_EXAMINE_OBJECT: /*   Lock,Fib            Bool       */
  448.         {
  449.             FIB *fib = BTOC (packet->dp_Arg2);
  450.                     CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  451.             CDROM_INFO info;
  452.  
  453.             if (obj->volume != g_volume) {
  454.               /* old lock from another disk: */
  455.               error = ERROR_OBJECT_NOT_FOUND;
  456.               break;
  457.             }
  458.             fib->fib_DiskKey = 0;
  459.             error = 0;
  460.             if (!CDROM_Info (obj, &info))
  461.               error = -1;
  462.             else
  463.               Fill_FileInfoBlock (fib, &info, obj->volume);
  464.         }
  465.         break;
  466.         case ACTION_INFO:        /*    Lock, InfoData      Bool:TRUE    */
  467.         tmp = BTOC(packet->dp_Arg2);
  468.         error = -1;
  469.         /*  fall through    */
  470.         case ACTION_DISK_INFO:  /*    InfoData      Bool:TRUE    */
  471.         {
  472.           if (Mount_Check ()) {
  473.             register INFODATA *id;
  474.  
  475.             (error) ? (id = tmp) : (id = BTOC (packet->dp_Arg1));
  476.             error = 0;
  477.             memset (id, 0, sizeof(*id));
  478.             id->id_DiskState = ID_WRITE_PROTECTED;
  479.             id->id_NumBlocks     = Volume_Size (g_volume);
  480.             id->id_NumBlocksUsed = id->id_NumBlocks;
  481.             id->id_BytesPerBlock = Block_Size (g_volume);
  482.             id->id_DiskType = ID_DOS_DISK;
  483.             id->id_VolumeNode = (long) CTOB (DevList);
  484.             id->id_InUse = 0;
  485.           }
  486.         }
  487.         break;
  488.         case ACTION_IS_FILESYSTEM:   /*  -                      Bool */
  489.           packet->dp_Res1 = DOSTRUE;
  490.           break;
  491.         case ACTION_PARENT:     /*     Lock                ParentLock */
  492.             {
  493.           if (Mount_Check ()) {
  494.             if (packet->dp_Arg1) {
  495.               CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  496.               CDROM_OBJ *parent;
  497.           
  498.               if (obj->volume != g_volume) {
  499.                 /* old lock from another disk: */
  500.                 error = ERROR_OBJECT_NOT_FOUND;
  501.                 break;
  502.               }
  503.               if (Is_Top_Level_Object (obj)) {
  504.                 packet->dp_Res1 = packet->dp_Res2 = 0;
  505.               } else {
  506.                 parent = Find_Parent (obj);
  507.                 if (!parent) {
  508.                   if (iso_errno == ISOERR_NO_MEMORY)
  509.                     error = ERROR_NO_FREE_STORE;
  510.                   else
  511.                     error = ERROR_OBJECT_NOT_FOUND;
  512.                 } else {
  513.                   packet->dp_Res1 = (long)
  514.                 CTOB (cdlock (parent, ACCESS_READ));
  515.                 }
  516.               }
  517.             } else
  518.               error = ERROR_OBJECT_NOT_FOUND;
  519.           } else
  520.             error = ERROR_NO_DISK;
  521.         }
  522.         break;
  523.         case ACTION_LOCATE_OBJECT:    /*   Lock,Name,Mode        Lock       */
  524.         {
  525.           if (Mount_Check ()) {
  526.             CDROM_OBJ *parentdir = getlockfile (packet->dp_Arg1);
  527.                     CDROM_OBJ *obj;
  528.             int offs;
  529.  
  530.             if (parentdir->volume != g_volume) {
  531.               /* old lock from another disk: */
  532.               error = ERROR_OBJECT_NOT_FOUND;
  533.               break;
  534.             }
  535.             btos (packet->dp_Arg2, buf);
  536. #ifndef NDEBUG
  537.             dbprintf ("'%s' %ld ", buf, packet->dp_Arg3);
  538.             if (strcmp(buf,"debugoff") == 0)
  539.             DBDisable = 1;
  540.             if (strcmp(buf,"debugon") == 0)
  541.             DBDisable = 0;
  542. #endif
  543.  
  544.             offs = Check_For_Volume_Name_Prefix (buf);
  545.             if (buf[offs]==0) {
  546.               if (parentdir)
  547.                 obj = Clone_Object (parentdir);
  548.               else
  549.                 obj = Open_Top_Level_Directory (g_volume);
  550.             } else
  551.               obj = Open_Object (parentdir, buf + offs);
  552.             
  553.             if (obj) {
  554.               packet->dp_Res1 = (long) CTOB (cdlock (obj, packet->dp_Arg3));
  555.             } else {
  556.               if (iso_errno == ISOERR_SCSI_ERROR) {
  557.                 error = ERROR_OBJECT_NOT_FOUND;
  558.             Unmount (FALSE);
  559.               } else if (iso_errno == ISOERR_ILLEGAL_NAME)
  560.             error = ERROR_INVALID_COMPONENT_NAME;
  561.               else if (iso_errno == ISOERR_NOT_FOUND)
  562.             error = ERROR_OBJECT_NOT_FOUND;
  563.               else if (iso_errno == ISOERR_NO_MEMORY)
  564.                 error = ERROR_NO_FREE_STORE;
  565.               else
  566.                 error = 333;
  567.             }
  568.           } else
  569.             error = ERROR_NO_DISK;
  570.         }
  571.         break;
  572.         case ACTION_COPY_DIR:   /*     Lock,                Lock       */
  573.             {
  574.           if (packet->dp_Arg1) {
  575.             CDROM_OBJ *obj = getlockfile (packet->dp_Arg1);
  576.             CDROM_OBJ *new = Clone_Object (obj);
  577.           
  578.             if (!new)
  579.               error = ERROR_NO_FREE_STORE;
  580.             else
  581.               packet->dp_Res1 = (long) CTOB (cdlock (new, ACCESS_READ));
  582.           } else
  583.             packet->dp_Res1 = 0;
  584.         }
  585.         break;
  586.         case ACTION_FREE_LOCK:  /*     Lock,                Bool       */
  587.         if (packet->dp_Arg1);
  588.             cdunlock (BTOC(packet->dp_Arg1));
  589.         break;
  590.         case ACTION_CURRENT_VOLUME: /* -                        DevList    */
  591.             packet->dp_Res1 = (long) CTOB (DevList);
  592.             break;
  593.         case ACTION_INHIBIT:    /*     Bool                Bool       */
  594.                 if (packet->dp_Arg1 == DOS_FALSE)
  595.           Check_Disk ();
  596.         break;
  597.         /*
  598.          *  FINDINPUT and FINDOUTPUT normally should return the
  599.          *  'write protected' error. If the field 'Name', however,
  600.          *  designates the root (e.g. CD0:), then the 'wrong type'
  601.          *  error should be returned. Otherwise, AmigaDOS would do
  602.          *  some funny things (such as saying 'Volume CD0: is write-
  603.          *  protected') if you try to mount the handler with the
  604.          *  field 'Mount' set to 1.
  605.          */
  606.         case ACTION_FINDOUTPUT: /*   Handle  Lock  Name         Bool       */
  607.         case ACTION_FINDUPDATE: /*   Handle  Lock  Name         Bool       */
  608.         {
  609.           int pos;
  610.           
  611.           btos(packet->dp_Arg3,buf);
  612.           BUG(dbprintf("'%s' ", buf);)
  613.           if ((pos = Check_For_Volume_Name_Prefix (buf)) &&
  614.               buf[pos] == 0)
  615.         error = ERROR_OBJECT_WRONG_TYPE;
  616.           else
  617.         error = ERROR_DISK_WRITE_PROTECTED;
  618.           break;
  619.         }
  620.         case ACTION_SAME_LOCK: /*    Lock  Lock                 Bool       */
  621.         {
  622.           CDROM_OBJ *obj1 = getlockfile(packet->dp_Arg1),
  623.                     *obj2 = getlockfile(packet->dp_Arg2);
  624.  
  625.               if (Same_Objects (obj1, obj2))
  626.                 packet->dp_Res1 = DOSTRUE;
  627.           else
  628.                 packet->dp_Res1 = DOSFALSE;
  629.  
  630.           break;
  631.         }
  632.         case ACTION_RENAME_DISK:
  633.         case ACTION_WRITE:
  634.         case ACTION_SET_PROTECT:
  635.         case ACTION_DELETE_OBJECT:
  636.         case ACTION_RENAME_OBJECT:
  637.         case ACTION_CREATE_DIR:
  638.         case ACTION_SET_COMMENT:
  639.         case ACTION_SET_DATE:
  640.         case ACTION_SET_FILE_SIZE:
  641.               error = ERROR_DISK_WRITE_PROTECTED;
  642.               break;
  643.         /*
  644.          *    A few other packet types which we do not support
  645.          */
  646.         case ACTION_MORE_CACHE: /*     #BufsToAdd            Bool       */
  647.         case ACTION_WAIT_CHAR:  /*     Timeout, ticks         Bool       */
  648.         case ACTION_FLUSH:        /*     writeout bufs, disk motor off           */
  649.         case ACTION_SCREEN_MODE:/*     Bool(-1:RAW 0:CON)        OldState   */
  650.         default:
  651.         error = ERROR_ACTION_NOT_KNOWN;
  652.         break;
  653.         }
  654.         if (packet) {
  655.         if (error) {
  656.             BUG(dbprintf("ERR=%ld\n", error);)
  657.             packet->dp_Res1 = DOS_FALSE;
  658.             packet->dp_Res2 = error;
  659.         } else {
  660.             BUG(dbprintf("RES=%06lx\n", packet->dp_Res1));
  661.         }
  662.         returnpacket(packet);
  663.         }
  664.     }
  665.     }
  666.     BUG(dbprintf("Can we remove ourselves? ");)
  667.     Delay(100);        /*    I wanna even see the debug message! */
  668.     Forbid();
  669.     if (packetsqueued() || g_files_pending ||
  670.         (g_volume && g_volume->locks)) {
  671.     Permit();
  672.     BUG(dbprintf(" ..  not yet!\n");)
  673.     notdone = 1;
  674.     goto top;        /*  sorry... can't exit     */
  675.     } else
  676.     BUG(dbprintf(" ..  yes!\n");)
  677.  
  678.     /* remove timer device and any pending timer requests: */
  679.     if (g_timer_sigbit)
  680.       Cleanup_Timer_Device ();
  681.  
  682.     /* this is getting dangerous. We will unload our very own
  683.      * code via UnLoadSeg() and need to keep the system in
  684.      * Forbid() state in order to avoid getting the free memory
  685.      * reclaimed by other tasks. This means: *NO* Wait() after
  686.      * Unmount(TRUE) ist called!
  687.      */
  688.  
  689.     Unmount (TRUE);
  690.     
  691.     dosfree ((ulong *) g_vol_name);
  692.  
  693.     Cleanup_CDROM (g_cd);
  694.  
  695.     Close_Intui ();
  696.  
  697.     /*
  698.      *    Remove debug process, closedown, fall of the end of the world
  699.      *    (which is how you kill yourself if a PROCESS.  A TASK would have
  700.      *    had to RemTask(NULL) itself).
  701.      */
  702.  
  703.     BUG2(dbuninit();)
  704.     if (UtilityBase)
  705.       CloseLibrary (UtilityBase);
  706.     if (DOSBase)
  707.       CloseLibrary ((struct Library *) DOSBase);
  708.     
  709.     return 0;
  710. }
  711.  
  712.  
  713. /*
  714.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  715.  *  can see by this and how the PACKET structure is extracted in the
  716.  *  GetMsg() of the main routine.
  717.  */
  718.  
  719. void returnpacket(struct DosPacket *packet)
  720. {
  721.     register struct Message *mess;
  722.     register struct MsgPort *replyport;
  723.  
  724.     replyport             = packet->dp_Port;
  725.     mess             = packet->dp_Link;
  726.     packet->dp_Port         = &DosProc->pr_MsgPort;
  727.     mess->mn_Node.ln_Name    = (char *)packet;
  728.     mess->mn_Node.ln_Succ    = NULL;
  729.     mess->mn_Node.ln_Pred    = NULL;
  730.     PutMsg(replyport, mess);
  731. }
  732.  
  733. /*
  734.  *  Are there any packets queued to our device?
  735.  */
  736.  
  737. int packetsqueued (void)
  738. {
  739.     return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
  740.         (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
  741. }
  742.  
  743. /*
  744.  *  DOS MEMORY ROUTINES
  745.  *
  746.  *  DOS makes certain assumptions about LOCKS.    A lock must minimally be
  747.  *  a FileLock structure, with additional private information after the
  748.  *  FileLock structure.  The longword before the beginning of the structure
  749.  *  must contain the length of structure + 4.
  750.  *
  751.  *  NOTE!!!!! The workbench does not follow the rules and assumes it can
  752.  *  copy lock structures.  This means that if you want to be workbench
  753.  *  compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
  754.  */
  755.  
  756. void *dosalloc(ulong bytes)
  757. {
  758.     register ulong *ptr;
  759.  
  760.     bytes += 4;
  761.     ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
  762.     *ptr = bytes;
  763.     return(ptr+1);
  764. }
  765.  
  766. void dosfree (ulong *ptr)
  767. {
  768.     --ptr;
  769.     FreeMem(ptr, *ptr);
  770. }
  771.  
  772. /*
  773.  *  Convert a BSTR into a normal string.. copying the string into buf.
  774.  *  I use normal strings for internal storage, and convert back and forth
  775.  *  when required.
  776.  */
  777.  
  778. void btos(LONG bstr, char *buf)
  779. {
  780.     unsigned char *str = BTOC(bstr);
  781.     bmov((char *) str+1, buf, *str);
  782.     buf[*str] = 0;
  783. }
  784.  
  785. /*
  786.  *  Some EXEC list handling routines not found in the EXEC library.
  787.  */
  788.  
  789. void *NextNode (NODE *node)
  790. {
  791.     node = node->mln_Succ;
  792.     if (node->mln_Succ == NULL)
  793.     return(NULL);
  794.     return(node);
  795. }
  796.  
  797. void *GetHead (LIST *list)
  798. {
  799.     if ((void *)list->mlh_Head != (void *)&list->mlh_Tail)
  800.     return(list->mlh_Head);
  801.     return(NULL);
  802. }
  803.  
  804. /*
  805.  *  The lock function.    The file has already been checked to see if it
  806.  *  is lockable given the mode.
  807.  */
  808.  
  809. LOCK *cdlock(CDROM_OBJ *cdfile, int mode)
  810. {
  811.   LOCK *lock = dosalloc (sizeof(LOCK));
  812.  
  813.   cdfile->volume->locks++;
  814.   lock->fl_Key = (long) cdfile;
  815.   lock->fl_Access = ACCESS_READ;
  816.   lock->fl_Task = &DosProc->pr_MsgPort;
  817.   lock->fl_Volume = (BPTR) CTOB (DevList);
  818.   return(lock);
  819. }
  820.  
  821. void cdunlock (LOCK *lock)
  822. {
  823.   CDROM_OBJ *obj = (CDROM_OBJ *) lock->fl_Key;
  824.  
  825.   if (--obj->volume->locks == 0 && !obj->volume->valid) {
  826.     Close_Volume (obj->volume);
  827.   }
  828.   Close_Object (obj);
  829.   dosfree ((ulong *) lock);                /* free lock        */
  830. }
  831.  
  832. /*
  833.  *  GETLOCKFILE(bptrlock)
  834.  *
  835.  *  Return the CDROM_OBJ (file or directory) associated with the
  836.  *  given lock, which is passed as a BPTR.
  837.  *
  838.  *  According to the DOS spec, the only way a NULL lock will ever be
  839.  *  passed to you is if the DosNode->dn_Lock is NULL, but I'm not sure.
  840.  *  In anycase, If a NULL lock is passed to me I simply assume it means
  841.  *  the root directory of the CDROM.
  842.  */
  843.  
  844. CDROM_OBJ *getlockfile (LONG lock)
  845. {
  846.   LOCK *rl = BTOC (lock);
  847.  
  848.   if (rl)
  849.     return (CDROM_OBJ *) rl->fl_Key;
  850.   return g_top_level_obj;
  851. }
  852.  
  853. /*
  854.  * If p_pathname contains a ':' character, return the position of the first
  855.  * character after ':'
  856.  * Otherwise, return 0.
  857.  */
  858.  
  859. int Check_For_Volume_Name_Prefix (char *p_pathname)
  860. {
  861.   char *pos = strchr (p_pathname, ':');
  862.   
  863.   return pos ? (pos - p_pathname) + 1 : 0;
  864. }
  865.  
  866. /*
  867.  * Fills a FileInfoBlock with the information contained in the
  868.  * directory record of a CD-ROM directory or file.
  869.  */
  870.  
  871. void Fill_FileInfoBlock (FIB *p_fib, CDROM_INFO *p_info, VOLUME *p_volume)
  872. {
  873.   char *src = p_info->name;
  874.   char *dest = p_fib->fib_FileName+1;
  875.   int len = p_info->name_length;
  876.  
  877.   p_fib->fib_DirEntryType = p_info->directory_f ? 2 : -3;
  878.   
  879.   /* I don't know exactly why I have to set fib_EntryType, but other
  880.    * handlers (e.g. DiskHandler by J Toebes et.al.) also do this.
  881.    */
  882.    
  883.   p_fib->fib_EntryType = p_fib->fib_DirEntryType;
  884.   
  885.   if (len == 1 && *src == ':') {
  886.     /* root of file system: */
  887.     p_fib->fib_DirEntryType = 2 /* was: 1 */;
  888.     /* file name == volume name: */
  889.     memcpy (p_fib->fib_FileName, g_vol_name, (int)(g_vol_name[0])+1);
  890.   } else {
  891.     /* copy file name: */
  892.     if (g_show_version_numbers) {
  893.       p_fib->fib_FileName[0] = len;
  894.       for (; len; len--)
  895.         *dest++ = *src++;
  896.     } else {
  897.       short i, real_len=len;
  898.       for (i=0; i<len; i++) {
  899.         if (*src == ';')
  900.       real_len = i;
  901.         *dest++ = *src++;
  902.       }
  903.       p_fib->fib_FileName[0] = real_len;
  904.     }
  905.  
  906.     if (g_map_to_lowercase && p_volume->protocol == PRO_ISO) {
  907.       /* convert ISO filename to lowercase: */
  908.       int i, len = p_fib->fib_FileName[0];
  909.       char *cp = p_fib->fib_FileName + 1;
  910.     
  911.       for (i=0; i<len; i++, cp++)
  912.         *cp = ToLower (*cp);
  913.     }
  914.   }
  915.   p_fib->fib_Protection = 0;
  916.   p_fib->fib_Size = p_info->file_length;
  917.   p_fib->fib_NumBlocks = p_info->file_length >> 11;
  918.   p_fib->fib_Comment[0] = 0;
  919.  
  920.   p_fib->fib_Date.ds_Days   = p_info->date / (24 * 60 * 60);
  921.   p_fib->fib_Date.ds_Minute = (p_info->date % (24 * 60 * 60)) / 60;
  922.   p_fib->fib_Date.ds_Tick   = (p_info->date % 60) * TICKS_PER_SECOND;
  923. }
  924.  
  925. /*
  926.  * Create Volume node and add to the device list. This will
  927.  * cause the WORKBENCH to recognize us as a disk. If we don't
  928.  * create a Volume node, Wb will not recognize us.
  929.  */
  930.  
  931. void Create_Volume_Node (LONG p_disk_type, ULONG p_volume_date)
  932. {
  933.   DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  934.   DEVLIST *dl;
  935.  
  936.   Forbid ();
  937.   DevList = dl = dosalloc(sizeof(DEVLIST));
  938.   dl->dl_Type = DLT_VOLUME;
  939.   dl->dl_Task = &DosProc->pr_MsgPort;
  940.   dl->dl_DiskType = p_disk_type;
  941.   dl->dl_Name = (BSTR) CTOB (g_vol_name);
  942.   dl->dl_VolumeDate.ds_Days = p_volume_date / (24 * 60 * 60);
  943.   dl->dl_VolumeDate.ds_Minute = (p_volume_date % (24 * 60 * 60)) / 60;
  944.   dl->dl_VolumeDate.ds_Tick = (p_volume_date % 60) * TICKS_PER_SECOND;
  945.   dl->dl_Next = di->di_DevInfo;
  946.   di->di_DevInfo = (long)CTOB(dl);
  947.   Permit ();
  948. }
  949.  
  950. /*
  951.  * Mount a volume.
  952.  */
  953.  
  954. void Mount (void)
  955. {
  956.   char buf[33];
  957.  
  958.   if (Has_Audio_Tracks (g_cd))
  959.     Show_CDDA_Icon ();
  960.  
  961.   g_volume = Open_Volume (g_cd, g_use_rock_ridge);
  962.   if (!g_volume) {
  963.     BUG(dbprintf ("!!! cannot open VOLUME !!!\n");)
  964. #if 0
  965.     strcpy (g_vol_name, "\9NoDosDisk");
  966.     Create_Volume_Node (ID_NOT_REALLY_DOS, 0);
  967.     Send_Event (TRUE);
  968. #endif
  969.     return;
  970.   } else {
  971.     g_disk_inserted = TRUE;
  972.     g_top_level_obj = Open_Top_Level_Directory (g_volume);
  973.     if (!g_top_level_obj) {
  974.       BUG(dbprintf ("!!! cannot open top level directory !!!\n");)
  975.       return;
  976.     }
  977.   }
  978.   
  979.   BUG(dbprintf ("***mounting*** ");)
  980.  
  981.   Volume_ID (g_volume, buf, sizeof (buf)-1);  
  982.   g_vol_name[0] = strlen (buf);
  983.   memcpy (g_vol_name+1, buf, strlen (buf));
  984.  
  985.   if (!(g_vol_name[0]))
  986.     memcpy (g_vol_name, "\7Unnamed", 8);
  987.  
  988.   /* AmigaDOS expects the BCPL string g_vol_name to be null-terminated: */
  989.   g_vol_name[(int)(g_vol_name[0])+1] = 0;
  990.  
  991.   Create_Volume_Node (ID_DOS_DISK, Volume_Creation_Date (g_volume));
  992.   Send_Event (TRUE);
  993. }
  994.  
  995. /*
  996.  *    Remove Volume entry.  Since DOS uses singly linked lists, we
  997.  *    must (ugg) search it manually to find the link before our
  998.  *    Volume entry.
  999.  */
  1000.  
  1001. void Unmount (int p_remove_device)
  1002. {
  1003.   DOSINFO *di;
  1004.   DEVLIST *dl;
  1005.   DEVNODE *dn;
  1006.   void *dlp;
  1007.  
  1008.   Hide_CDDA_Icon ();
  1009.  
  1010.   Forbid ();
  1011.   di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
  1012.  
  1013.   if (DevList) {
  1014.     dlp = &di->di_DevInfo;
  1015.     for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
  1016.       dlp = &dl->dl_Next;
  1017.     if (dl == DevList) {
  1018.       *(BPTR *)dlp = dl->dl_Next;
  1019.       dosfree((ulong *) dl);
  1020.     } else {
  1021.       BUG(dbprintf("****PANIC: Unable to find volume node\n");)
  1022.     }
  1023.  
  1024.     if (DevList->dl_DiskType != ID_NOT_REALLY_DOS) {
  1025.       Close_Object (g_top_level_obj);
  1026.       if (g_volume->locks == 0)
  1027.         Close_Volume (g_volume);
  1028.       else {
  1029.         g_volume->valid = 0;
  1030.       }
  1031.     }
  1032.  
  1033.     DevList = NULL;
  1034.   }
  1035.  
  1036.   Send_Event (FALSE);
  1037.  
  1038.   g_volume = 0;
  1039.  
  1040.   /* when the handler code exits the corresponding device
  1041.    * node (e.g. "CD0") will be modified. The handler code
  1042.    * will be unloaded and the task entry will be set to
  1043.    * zero, so the next device access will reload and
  1044.    * restart the handler code.
  1045.    */
  1046.  
  1047.   if (p_remove_device) {
  1048.     di = BTOC (((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  1049.     dlp = &di->di_DevInfo;
  1050.     dn = BTOC (di->di_DevInfo);
  1051.  
  1052.     while (dn) {
  1053.       if (dn->dn_Task == DosTask) {
  1054.         BUG(dbprintf("got it! %b\n",dn->dn_Name);)
  1055.     if (TypeOfMem (BADDR (dn->dn_SegList))) {
  1056.       UnLoadSeg (dn->dn_SegList);
  1057.       dn->dn_SegList = 0;
  1058.     } else
  1059.       BUG(dbprintf("not a valid seglist\n");)
  1060.  
  1061.     dn->dn_Task = NULL;
  1062.  
  1063.         *(BPTR *) dlp = dn->dn_Next;
  1064.         dosfree ((ulong *) dn);
  1065.  
  1066.     break;
  1067.       }    else {
  1068.         dlp = &dn->dn_Next;
  1069.     dn = BTOC (dn->dn_Next);
  1070.       }
  1071.     }
  1072.   } else
  1073.     Permit ();
  1074. }
  1075.  
  1076. /*
  1077.  * Mount_Check returns 1 if a valid disk is inserted in the drive. A check is
  1078.  * only performed if previously the drive was empty.
  1079.  */
  1080.  
  1081. int Mount_Check (void)
  1082. {
  1083.   if (!g_disk_inserted) {
  1084.    /*
  1085.     * No disk was inserted up to now: we will check whether
  1086.     * a disk has been inserted by sending the test unit ready
  1087.     * command. We have to send the command twice because
  1088.     * the first SCSI command after inserting a new disk is
  1089.     * always rejected.
  1090.     */
  1091.     if (Test_Unit_Ready (g_cd) ||
  1092.         Test_Unit_Ready (g_cd)) {
  1093.       g_disk_inserted = TRUE;
  1094.       Mount ();
  1095.     } else {
  1096.       return 0;
  1097.     }
  1098.     if (DevList)
  1099.       return 1;
  1100.     else {
  1101.       /* Mount() did not succeed: */
  1102.       return 0;
  1103.     }
  1104.   }
  1105.   return 1;
  1106. }
  1107.  
  1108. /*
  1109.  *  Open timer device structures:
  1110.  */
  1111.  
  1112. int Open_Timer_Device (void)
  1113. {
  1114.   if (!(g_timer_mp = CreateMsgPort ())) {
  1115.     BUG(dbprintf ("cannot create timer message port!\n");)
  1116.     return 0;
  1117.   }
  1118.   if (!(g_timer_io = (struct timerequest *)
  1119.        CreateIORequest (g_timer_mp, sizeof (struct timerequest)))) {
  1120.     BUG(dbprintf ("cannot create timer i/o structure!\n");)
  1121.     DeleteMsgPort (g_timer_mp);
  1122.     return 0;
  1123.   }
  1124.   if (OpenDevice ((UBYTE *) TIMERNAME, UNIT_VBLANK,
  1125.             (struct IORequest *) g_timer_io, 0)) {
  1126.     BUG(dbprintf ("cannot open timer device!\n");)
  1127.     DeleteIORequest ((struct IORequest *) g_timer_io);
  1128.     DeleteMsgPort (g_timer_mp);
  1129.     return 0;
  1130.   }
  1131.   g_timer_sigbit = 1L << g_timer_mp->mp_SigBit;
  1132.   return 1;
  1133. }
  1134.  
  1135. /*
  1136.  *  Remove timer device structures:
  1137.  */
  1138.  
  1139. void Cleanup_Timer_Device (void)
  1140. {
  1141.   /* remove any pending requests: */
  1142.   if (!CheckIO ((struct IORequest *) g_timer_io))
  1143.     AbortIO ((struct IORequest *) g_timer_io);
  1144.   WaitIO ((struct IORequest *) g_timer_io);
  1145.   
  1146.   CloseDevice ((struct IORequest *) g_timer_io);
  1147.   DeleteIORequest ((struct IORequest *) g_timer_io);
  1148.   DeleteMsgPort (g_timer_mp);
  1149. }
  1150.  
  1151. /*
  1152.  *  Send timer request
  1153.  */
  1154.  
  1155. void Send_Timer_Request (void)
  1156. {
  1157.   g_timer_io->tr_node.io_Command = TR_ADDREQUEST;
  1158.   g_timer_io->tr_time.tv_secs = g_scan_interval;
  1159.   g_timer_io->tr_time.tv_micro = 0;
  1160.   SendIO ((struct IORequest *) g_timer_io);
  1161. }
  1162.  
  1163. /*
  1164.  *  Check whether the disk has been removed or inserted.
  1165.  */
  1166.  
  1167. void Check_Disk (void)
  1168. {
  1169.   BUG(dbprintf ("Checking Disk... ");)
  1170.   if (g_disk_inserted) {
  1171.     if (Test_Unit_Ready (g_cd)) {
  1172.       BUG(dbprintf ("no disk change  "));
  1173.     } else {
  1174.       g_disk_inserted = FALSE;
  1175.       BUG(dbprintf ("disk has been removed  ");)
  1176.       if (DevList)
  1177.         Unmount (FALSE);
  1178.       Hide_CDDA_Icon ();
  1179.     }
  1180.   }
  1181.   if (!g_disk_inserted) {
  1182.     if (Test_Unit_Ready (g_cd) ||
  1183.         Test_Unit_Ready (g_cd)) {
  1184.       g_disk_inserted = TRUE;
  1185.       BUG(dbprintf ("disk has been inserted");)
  1186.       Mount ();
  1187.     }
  1188.   }
  1189.   BUG(dbprintf ("\n");)
  1190. }
  1191.  
  1192. /* The following lines will generate a `disk inserted/removed' event, in order
  1193.  * to get Workbench to rescan the DosList and update the list of
  1194.  * volume icons.
  1195.  */
  1196.  
  1197. void Send_Event (int p_inserted)
  1198. {
  1199.   struct IOStdReq *InputRequest;
  1200.   struct MsgPort *InputPort;
  1201.  
  1202.   if (InputPort = (struct MsgPort *) CreateMsgPort ()) {
  1203.     if (InputRequest = (struct IOStdReq *)
  1204.         CreateIORequest (InputPort, sizeof (struct IOStdReq))) {
  1205.       if (!OpenDevice ((UBYTE *) "input.device", 0,
  1206.                      (struct IORequest *) InputRequest, 0)) {
  1207.     static struct InputEvent InputEvent;
  1208.  
  1209.     memset (&InputEvent, 0, sizeof (struct InputEvent));
  1210.  
  1211.     InputEvent.ie_Class = p_inserted ? IECLASS_DISKINSERTED :
  1212.                        IECLASS_DISKREMOVED;
  1213.  
  1214.     InputRequest->io_Command = IND_WRITEEVENT;
  1215.     InputRequest->io_Data = &InputEvent;
  1216.     InputRequest->io_Length = sizeof (struct InputEvent);
  1217.  
  1218.     DoIO ((struct IORequest *) InputRequest);
  1219.  
  1220.     CloseDevice ((struct IORequest *) InputRequest);
  1221.       }
  1222.       DeleteIORequest (InputRequest);
  1223.     }
  1224.     DeleteMsgPort (InputPort);
  1225.   }
  1226. }
  1227.  
  1228.  
  1229.